//
// Created by martin on 2021/5/30.
//

#include <unistd.h>
#include <limits.h>
#include <sys/resource.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>

#include "directory.h"

#ifndef PATH_MAX
#define PATH_MAX   1024
#endif

#if 0
struct dirent {
    ino_t d_ino;       /* Inode number */
    off_t d_off;       /* Not an offset; see below */
    unsigned short d_reclen;    /* Length of this record */
    unsigned char d_type;      /* Type of file; not supported
                                              by all filesystem types */
    char d_name[256]; /* Null-terminated filename */
};
#endif

/**
 * 递归遍历目录
 * @param basedir 当前基准目录路径
 * @param callback 对当前文件要进行的操作
 * @return 返回遍历结果
 * - 0 遍历成功
 * - < 0 遍历失败
 */
int directory_walk(char *basedir, void (*callback)(char *, char *))
{
    if (basedir == NULL) return -1;
    if (strlen(basedir) > PATH_MAX) {
        fprintf(stderr, "dir is too long\n");
        return -2;
    }

    char name[PATH_MAX];
    char type[40];

    DIR *dirp;
    dirp = opendir(basedir);
    if (dirp < 0) {
        perror("opendir error");
        return -3;
    }

    struct dirent * dp;
    while ((dp = readdir(dirp)) != NULL) {
        /* 排除当前目录".", 上一级目录".." */
        if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
            continue;
        }

        if (strlen(basedir) + strlen(dp->d_name) + 2 > sizeof(name)) {
            fprintf(stderr, "directory_walk:  %s/%s name is too long\n", basedir, dp->d_name);
            return -4;
        } else {
            sprintf(name, "%s/%s", basedir, dp->d_name);

            switch (dp->d_type) {
                case DT_DIR:
                    strcpy(type, "directory");
                    directory_walk(name, callback);
                    break;
                case DT_REG:
                    strcpy(type, "regular file");
                    break;
                default:
                    strcpy(type, "unknow file type");
            }

            if (callback) {
                callback(name, type);
            }
        }
    }

    closedir(dirp);

    return 0;
}